#!/usr/bin/env groovy
import static javax.swing.JOptionPane.*
import javax.swing.*
import net.miginfocom.swing.*
import java.util.prefs.*
import com.genzou.convert.*

class FileReplacerController {
    // these will be injected by Griffon
    def model
    def view
    final def ANT = new AntBuilder()
    final def PREFERENCES = Preferences.userRoot().node("fileReplacer")
    final def PREFERENCES_LIST = [ "dir", "includes", "excludes", "token", "replace", "encoding", "useRegexp", "doNotInSubdirectories", "ignoreDotFile", "ignoreCase", "doBackup" ]
    //final def PREFERENCES_LIST = [ "dir", "includes", "excludes", "token", "replace", "encoding"  ]
    final def FORMAT_PATERN = "yyyyMMdd-HHmmss"
    final def BACKUP_DIR = new File(System.properties["java.io.tmpdir"] + "/fileReplacer")
    final def convertor = new Convertor<File>()
    
    void mvcGroupInit(Map args) {
        // this method is called after model and view are injected
        
    }
    
    def save = { evt ->
        if( showConfirmDialog( view.rootPane, "Save conditions?") != YES_OPTION )
            return
        
        def finalize = { id ->
            switch(model[id]){
                case Boolean:
                    PREFERENCES.putBoolean(id, model[id])
                    break
                default:
                    PREFERENCES.put(id, model[id])
                    break
            }
        }
        PREFERENCES_LIST.each{
            finalize(it)
        }
        PREFERENCES.flush()
        showMessageDialog( view.rootPane, "saved.")
    }
    
    def windowOpened = { evt ->
        def initialize = { id ->
            switch(model[id]){
                case Boolean:
                    model[id] = PREFERENCES.getBoolean(id, true)
                    break
                default:
                    model[id] = PREFERENCES.get(id, "")
                    break
            }
        }
        PREFERENCES_LIST.each{
            initialize(it)
            view[it].reverseUpdate()
        }
        
        reviewHistories()
    }
    
    def reviewHistories(){
        model.histories = BACKUP_DIR.listFiles().collect{
            Date.parse(FORMAT_PATERN, it.name).format("yyyy/MM/dd HH:mm:ss")
        } as Vector
    }
    
    def clearHistories = { evt ->
        if( showConfirmDialog( view.rootPane, "clear backups?") != YES_OPTION )
            return
        
        BACKUP_DIR.listFiles().each{ dir ->
            ANT.delete(dir:dir)
        }
        
        reviewHistories()
        showMessageDialog(view.rootPane, "cleared backups.")
    }
    
    def focusGainedForHistories = { evt ->
        model.canRestoreHistory = true
    }
    
    def focusLostForHistories = { evt ->
        if( !evt.component.selectedValue ){
            model.canRestoreHistory = false
        }
    }
    
    def restoreHistory = { evt ->
        if (view.fileChooser.showOpenDialog() != JFileChooser.APPROVE_OPTION){
            return
        }
        if( showConfirmDialog( view.rootPane, "revert?\n" + view.fileChooser.selectedFile ) != YES_OPTION ){
            return
        }
        
        doOutside{
            def histName = Date.parse("yyyy/MM/dd HH:mm:ss", view.histories.selectedValue).format(FORMAT_PATERN)
            ANT.copy(todir:view.fileChooser.selectedFile, overwrite:true){
                fileset(dir:"${BACKUP_DIR}/${histName}")
            }
            edt{
                model.canRestoreHistory = false
                showMessageDialog(view.rootPane, "reverted")
            }
        }
    }
    
    def clickUseRegexp = { evt ->
        if( !model.useRegexp ){
            model.ignoreCase = false
        }
    }
    
    def replace = { evt ->
        model.with{
            try{
                // initialize
                def now = new Date()
                message = ""
                resultList = ""
                encoding = encoding.trim()?:System.properties."file.encoding"
                replace = replace?:""
                
                if( !dir ){
                    throw new IllegalArgumentException("select no directories.")
                }
                if( !token ){
                    throw new IllegalArgumentException("input no conditions")
                }
                
                if( showConfirmDialog( view.rootPane, "replace?") != YES_OPTION ){
                    return
                }
                message = "please wait..."
                
                doOutside{
                    def tokenText = token
                    
                    convertor.clear()
                    convertor.filters << {
                        it.file &&
                        !(ignoreDotFile && it.path.contains(File.separator + ".")) &&
                        it.name.contains(includes) &&
                        !(excludes && it.name.contains(excludes))
                    }
                    convertor.backuper = {
                        if( doBackup ){
                            def backup = new File(System.properties["java.io.tmpdir"] + "/fileReplacer/${now.format(FORMAT_PATERN)}" + (it.path - dir))
                            if( !backup.parentFile.exists() ){
                                backup.parentFile.mkdirs()
                            }
                            backup << it.readBytes()
                            backup
                        } else {
                            it
                        }
                    }
                    
                    if( useRegexp ){
                        tokenText = (ignoreCase?"(?i)":"") + token
                        convertor.filters << {
                            it.getText(encoding) =~ tokenText
                        }
                        convertor.convertors << {
                            it.write(it.getText(encoding).replaceAll(tokenText, replace), encoding)
                            it
                        }
                    } else {
                        convertor.filters << {
                            it.getText(encoding).contains(tokenText)
                        }
                        convertor.convertors << {
                            it.write(it.getText(encoding).replace(tokenText, replace), encoding)
                            it
                        }
                    }
                    
                    def files = []
                    new File(dir).eachFileRecurse{
                        files << it
                    }
                    convertor.convert(files)
                    
                    edt{
                        model.message = "[ ${convertor.convertedObjects.size()} ] files has been replaced"
                        model.resultList = convertor.convertedObjects*.path.join("\n")
                        reviewHistories()
                    }
                }
            }catch ( e ){
                showMessageDialog( view.rootPane, e.message)
                return
            } finally {
                //
            }
        }
    }
    
    def searchDirectory = { evt ->
        def dir = new File(model.dir)
        if( dir?.exists() ){
            view.fileChooser.currentDirectory = dir.directory?dir:dir.parentFile
        }
        if (view.fileChooser.showOpenDialog() != JFileChooser.APPROVE_OPTION){
            return
        }
        model.dir = view.fileChooser.selectedFile
        view.dir.reverseUpdate()
    }
    
}